package util;
/**
 * 单线程扫描和删除无需等待,扫描到null元素并不代表集合为空
 * 多线程添加仍然是串行话
 */

import java.util.concurrent.atomic.AtomicInteger;

public class UnlockQueue<O> {
    private Entry header = null;
    private Entry tail = null;

    public class Entry{
        private O value;
        public Entry pre;
        public Entry next;
        public Entry(O o){
            this.value = o;
        }
        public O getValue(){
            return value;
        }
    }
    private AtomicInteger size = new AtomicInteger(0);
    public int size() {
        return size.get();
    }

    public boolean isEmpty() {
        return size.get() <= 0;
    }



    public synchronized boolean add(O o) {
        Entry entry = new Entry(o);
        Entry _tail = tail;
        entry.pre = tail;
        entry.next = null;
        if(header == null &&  tail == null){
            header = entry;
            tail = entry;
        }else {
            tail = entry;
            _tail.next = entry;
        }

        size.getAndIncrement();
        return true;
    }

    public boolean remove(Entry o) {
        if(o.pre == null &&  o.next == null){
            header = null;
            tail = null;
        }else if(o == header){
            header = o.next;
            header.pre = null;
        }else if(o == tail){
            o.pre.next = null;
            tail = o.pre;
        }else {
            o.pre.next = o.next;
            o.next.pre = o.pre;
        }
        size.getAndDecrement();
        o = null;
        return true;
    }
    public volatile Entry scan = header;
    public Entry next(){
        Entry _scan = scan;
        if(scan != null){
            scan = scan.next;
        }else {
            scan = header;
        }

        return _scan;
    }

    public O nextValue(){
        Entry _scan = scan;
        if(scan != null){
            scan = scan.next;
        }else {
            scan = header;
        }

        return _scan.value;
    }

    public static void main(String[] args) {
        UnlockQueue<Integer> integerUnlockQueue = new UnlockQueue<>();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                boolean interrupted_flag = false;
                while (true) {
                    UnlockQueue.Entry next =  integerUnlockQueue.next();
                    if (next != null) {

                        if(System.currentTimeMillis() % 2 == 0){
                            System.out.println(next.value);
                            integerUnlockQueue.remove(next);
                        }else {
                            System.out.println(next.value + " not finished");
                        }

                    }else {
                        //System.out.println("null");
                        System.out.println("queue is empty  ");
                    }
                    try {
                        Thread.sleep(10L);
                    } catch (InterruptedException e) {
                        interrupted_flag = true;
                    }
                    if(interrupted_flag){
                        if(integerUnlockQueue.isEmpty())
                            break;
                    }
//                    if(integerUnlockQueue.isEmpty()){
//                        System.out.println("queue is empty  ");
//                    }
                }
            }
        });
        //thread.setDaemon(true);
        thread.start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    integerUnlockQueue.add(i);
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 100; i < 200; i++) {
                    integerUnlockQueue.add(i);
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        thread1.start();
        try {
            thread1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();

        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.exit(0);
    }

}
